package cn.ibizlab.odoo.activiti.service.impl;

import com.alibaba.fastjson.JSONObject;
import cn.ibizlab.odoo.activiti.service.IWFCoreService;
import cn.ibizlab.odoo.activiti.service.external.UniWFService;
import cn.ibizlab.odoo.activiti.util.*;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class WFCoreService implements IWFCoreService {

    @Autowired
    ProcessRuntime  processRuntime;
    @Autowired
    TaskRuntime taskRuntime;
    @Autowired
    RepositoryService repositoryService;
    @Autowired
    HistoryService historyService;
    @Autowired
    SecurityUtil securityUtil;
    @Autowired
    WFGoToUtil wfGoToUtil;
    @Autowired
    TaskService taskService;
    @Autowired
    UniWFService uniWfService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    WFStepUtil wfStepUtil;
    @Autowired
    UniWFService uniWFService;

    @Override
    public JSONObject wfStart(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));
        //流程启动参数检查
        JSONObject paramValid = WFStartParamValid(et);
        if(!ObjectUtils.isEmpty(paramValid))
            return paramValid;

        //获取部署标识
        String deployId=et.getString("srfdeployid");

        ProcessDefinition processDef=repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
        if(ObjectUtils.isEmpty(processDef))
            return WFResultUtil.error(String.format("未能查询到[%s]流程定义",deployId)) ;

        //准备流程所需参数
        Map<String, Object> variables = getVariables(et);
        //根据流程定义启动流程
        org.activiti.engine.runtime.ProcessInstance instance = runtimeService.startProcessInstanceById(processDef.getId(), variables);//流程定时标识、业务标识、变量

        if(ObjectUtils.isEmpty(instance))
            return WFResultUtil.error("启动流程失败") ;

        return  WFResultUtil.success("流程启动成功") ;
    }

    @Override
    public JSONObject wfSubmit(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));
        //流程提交参数检查
        JSONObject paramValid = WFSubmitParamValid(et);
        if(!ObjectUtils.isEmpty(paramValid))
            return paramValid;

        //获取当前提交的任务标识
        String taskId=et.getString("srfwfengineworklistid");
        //准备流程所需参数
        Map<String, Object> variables=getVariables(et);
        //查询当前提交任务是否存在
        org.activiti.engine.task.Task cur_task = taskService.createTaskQuery().taskId(taskId).singleResult();

        if(ObjectUtils.isEmpty(cur_task)){
            return WFResultUtil.error(String.format("未能查找到[%s]对应的任务",taskId)) ;
        }
        //完成任务
        taskService.complete(taskId, variables,true);

        return WFResultUtil.success("流程提交成功");

    }


    @Override
    public JSONObject wfGoto(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));
        //源任务标识
        String processInstanceId=et.getString("processinstanceid");
        //目标任务标识
        String wfStepId=et.getString("wfstepid");

        if(StringUtils.isEmpty(processInstanceId) || StringUtils.isEmpty(wfStepId)){
            return WFResultUtil.error("参数输入错误，请求参数中需包含流程实例标识[processInstanceId]与目标步骤节点标识[wfStepId]");
        }

        //执行流程跳转操作
        wfGoToUtil.jump(processInstanceId,String.format("ACTIVITI%s",wfStepId));

        return WFResultUtil.success("流程跳转成功");
    }

    @Override
    public JSONObject wfClose(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));

        //流程关闭参数检查
        JSONObject paramValid=WFCloseParamValid(et);
        if(!ObjectUtils.isEmpty(paramValid))
            return paramValid;

        //获取当前流程实例信息
        JSONObject uniwfInstance=et.getJSONObject("srfwfinstance");
        //获取当前流程实例标识
        String instanceId=uniwfInstance.getString("wfengineinstanceid");

        //停止流程实例
        runtimeService.deleteProcessInstance(instanceId,"终止流程");

        return WFResultUtil.success("流程成功中止");
    }

//    @Override
//    public String wfRollback(JSONObject et) {
//
//        //流程实例标识
//        String instanceId =et.getString("instanceid");
//
//        if(StringUtils.isEmpty(instanceId) ){
//            return "参数输入错误，请求参数中需包含 当前流程步骤标识：[instanceid]";
//        }
//
//        //当前任务
//       // org.activiti.engine.task.Task curTask = taskService.createTaskQuery().processInstanceId(instanceId).singleResult();
//
//        //前一步任务
//        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).orderByTaskCreateTime().desc().list();
//
//        if(ObjectUtils.isEmpty(historicTaskInstances) || historicTaskInstances.size()<2)
//            return "历史步骤不存在，不允许退回";
//
//        HistoricTaskInstance hisTaskInst=historicTaskInstances.get(1);
//
//        org.activiti.engine.task.Task hisTask=wfGoToUtil.historicTask2Task(hisTaskInst);
//
//        //将流程退回到上一步骤
//        wfGoToUtil.jump(instanceId,hisTask.getTaskDefinitionKey());
//
//        return "流程撤回成功";
//
//    }

//    @Override
//    public String wfSendBack(JSONObject et) {//主1
//
//        //流程实例标识
//        String instanceid =et.getString("instanceid");
//
//        if(StringUtils.isEmpty(instanceid) ){
//            return "参数输入错误，请求参数中需包含 当前流程步骤标识：[instanceid]";
//        }
//
//        //当前任务
//        org.activiti.engine.task.Task curTask = taskService.createTaskQuery().processInstanceId(instanceid).singleResult();
//
//        //前一步任务
//        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceid).orderByTaskCreateTime().desc().list();
//
//        if(ObjectUtils.isEmpty(historicTaskInstances) || historicTaskInstances.size()<2)
//            return "流程退回失败，未能正常查询到前一步流程信息";
//
//        HistoricTaskInstance hisTaskInst=historicTaskInstances.get(1);
//
////        org.activiti.engine.task.Task hisTask=wfGoToUtil.historicTask2Task(hisTaskInst);
//
//        //将流程退回到上一步骤
////        wfGoToUtil.jump(curTask,hisTask);
//
//        return "流程退回成功";
//
//    }
//
//    @Override
//    public String wfReassign(JSONObject et) {
//
//        //任务标识
//        String taskId=et.getString("taskid");
//
//        //旧任务审批
//        String old_assign=et.getString("old_assign");
//
//        //新任务审批人
//        String new_assign=et.getString("new_assign");
//
//        if(StringUtils.isEmpty(taskId) ||  StringUtils.isEmpty(old_assign) || StringUtils.isEmpty(new_assign) )
//            return "参数输入错误，请求参数中需包含 [taskid]、[old_assign]、[new_assign] ";
//
//        //移除旧任务审批人
//        taskService.deleteCandidateUser(taskId,old_assign);
//
//        //添加新任务审批人
//        taskService.addCandidateUser(taskId,new_assign);
//
//        return "重置审批人员成功";
//    }
//
//    @Override
//    public void wfMarkRead(JSONObject et) {
//        //暂未实现
//    }

    /**
     * 流程挂起
     */
    @Override
    public JSONObject wfSuspend(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));

        //流程实例标识
        String srfWFInstanceId=et.getString("srfwfinstanceid");

        if(StringUtils.isEmpty(srfWFInstanceId))
            return WFResultUtil.error(String.format("参数输入错误，请求参数中需包含 [srfwfinstanceid]")) ;

        //流程挂起
        runtimeService.suspendProcessInstanceById(srfWFInstanceId);

        return WFResultUtil.success("流程已挂起");
    }

    /**
     * 流程恢复
     */
    @Override
    public JSONObject wfResume(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs(et.getString("srfuserid"));

        //流程实例标识
        String srfWFInstanceId=et.getString("srfwfinstanceid");

        if(StringUtils.isEmpty(srfWFInstanceId))
            return WFResultUtil.error(String.format("参数输入错误，请求参数中需包含 [instanceid]")) ;

        //流程恢复
        runtimeService.activateProcessInstanceById(srfWFInstanceId);

        return WFResultUtil.success("流程已恢复");
    }

    @Override
    public JSONObject wfDeploy(JSONObject et) {

        //系统标识
        String systemId=et.getString("serviceid");
        //工作流标识
        String wfId=et.getString("wfid");
        //工作流名称
        String wfName=et.getString("wfname");
        //工作流版本
        String wfverId=et.getString("wfverid");
        //工作流文件名
        String fileName=et.getString("filename");
        //工作流文件(bpmn)内容
        byte[] fileContent=et.getBytes("filecontent");

        if( StringUtils.isEmpty(systemId) ||  StringUtils.isEmpty(wfId)  ||  StringUtils.isEmpty(wfverId) || ObjectUtils.isEmpty(fileContent ) )
            WFResultUtil.error(String.format("部署 [%s|%s|%s|%s] 流程发生错误，参数 [serviceId]、[wfid]、[wfverid]、[fileName] 值不允许为空",systemId,wfId,wfName,wfverId));

        Deployment deploy = repositoryService.createDeployment().addBytes(fileName,fileContent).key(wfId).name(wfName).tenantId(systemId).category(wfverId).deploy();
        JSONObject resultData =WFResultUtil.success("部署成功");
        resultData.put("deployid",deploy.getId());

        return resultData;
    }

    /**
     * 填充流程参数
     * @param et
     * @return
     */
    private Map<String, Object> getVariables(JSONObject et) {

        Map<String, Object> instanceVariables = new HashMap<>();

        //流程实例标识
        String srfWFInstanceId = et.getString("srfwfinstanceid");
        //流程操作标识
        String srfConnection= et.getString("srfconnection");
        //待办URL
        String srfViewURL=et.getString("srfviewurl");
        //业务数据
        JSONObject srfBOData = et.getJSONObject("srfbodata");
        //流程数据
        JSONObject srfWFData = et.getJSONObject("srfwfdata");
        //审批意见
        String srfWFMemo=et.getString("srfwfmemo");

        if(!StringUtils.isEmpty(srfWFData)){
            instanceVariables.putAll(getWFVariables(srfWFData));
        }
        if(!StringUtils.isEmpty(srfBOData)){
            instanceVariables.putAll(getBOVariables(srfBOData));
        }
        if(!StringUtils.isEmpty(srfViewURL)){
            instanceVariables.put("srfviewurl",srfViewURL);
        }
        if(!StringUtils.isEmpty(srfConnection)){
            instanceVariables.put("srfconnection",srfConnection);
        }
        if(!StringUtils.isEmpty(srfWFInstanceId)){
            instanceVariables.put("srfwfinstanceid",srfWFInstanceId);
        }
        if(!StringUtils.isEmpty(srfWFMemo)){
            instanceVariables.put("srfwfmemo",srfWFMemo);
        }

        return instanceVariables;
    }

    /**
     * 业务参数转换
     * @param boData
     * @return
     */
    private JSONObject getBOVariables(JSONObject boData){

        JSONObject boJsonObj=new JSONObject();

        if(ObjectUtils.isEmpty(boData))
            return boJsonObj;

        for(String boKey : boData.keySet()){
            Object boValue = boData.get(boKey);
            if(!ObjectUtils.isEmpty(boValue)){
                boJsonObj.put(String.format("%s",boKey.toLowerCase()),boValue);
                boJsonObj.put(String.format("%s__%s","bo",boKey.toLowerCase()),boValue);
            }
        }
        return boJsonObj;
    }

    /**
     * 流程参数转换
     * @param wfData
     * @return
     */
    private JSONObject getWFVariables(JSONObject wfData){

        JSONObject wfJsonObj=new JSONObject();

        if(ObjectUtils.isEmpty(wfData))
            return wfJsonObj;

        for(String wfKey : wfData.keySet()){
            Object wfValue = wfData.get(wfKey);
            if(!ObjectUtils.isEmpty(wfValue)){
                wfJsonObj.put(String.format("%s",wfKey.toLowerCase()),wfValue);
                wfJsonObj.put(String.format("%s__%s","wf",wfKey.toLowerCase()),wfValue);
            }
        }

        return wfJsonObj;
    }

    /**
     * 流程启动参数检查
     * @param startParam
     * @return
     */
    private JSONObject WFStartParamValid(JSONObject startParam){

        JSONObject result=null;

        String srfWFInstanceId=startParam.getString("srfwfinstanceid");
        String srfDeployId=startParam.getString("srfdeployid");

        if (StringUtils.isEmpty(srfDeployId) ||  ObjectUtils.isEmpty(srfWFInstanceId) )
            return WFResultUtil.error("参数输入错误，请求参数中需包含 [srfdeployid] 、[srfwfinstanceid]  ") ;

        return result;
    }

    /**
     *  流程提交参数检查
     * @param submitParam
     * @return
     */
    private JSONObject WFSubmitParamValid(JSONObject submitParam){

        JSONObject result = null;

        String srfWFInstanceId=submitParam.getString("srfwfinstanceid");

        String srfWFEngineWorklistId=submitParam.getString("srfwfengineworklistid");

        String srfConnection=submitParam.getString("srfconnection");

        if (StringUtils.isEmpty(srfWFInstanceId) ||  StringUtils.isEmpty(srfWFEngineWorklistId)  ||StringUtils.isEmpty(srfConnection))
            return  WFResultUtil.error("参数输入错误，请求参数中需包含 [srfwfinstanceid]、[srfwfengineworklistid]、[srfconnection]") ;

        return result;

    }

    /**
     * 流程关闭参数检查
     * @param closeParam
     * @return
     */
    private JSONObject  WFCloseParamValid(JSONObject closeParam){

        JSONObject result = null;
        //流程实例标识
        String srfWFInstanceId=closeParam.getString("srfwfinstanceid");

        //获取当前流程实例标识
        String srfWFEngineInstanceId=closeParam.getString("srfwfengineinstanceid");

        if(ObjectUtils.isEmpty(srfWFInstanceId) || StringUtils.isEmpty(srfWFEngineInstanceId) )
            return  WFResultUtil.error("参数输入错误，请求参数中需包含[srfwfinstanceid] 、[srfwfengineinstanceid] ") ;

        return result;
    }

}
